﻿using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
using Microsoft.DirectX.DirectSound;
using Microsoft.Samples.DirectX.UtilityToolkit;
using System.IO;
using WiimoteLib;

namespace WiiShooter
{
    class Game : System.Windows.Forms.Form
    {
        //Variables controlling display elements
        // Hardware device.
        private Microsoft.DirectX.Direct3D.Device device;
        public static Microsoft.DirectX.DirectSound.Device soundDevice;
        public static int screenResolutionWidth;
        public static int screenResolutionHeight;
        // Run fullscreen or window.
        private Boolean windowed = true;
        private System.ComponentModel.Container components = null;
        private Microsoft.DirectX.DirectInput.Device keyboard;
        // Variables for RenderText method.
        int lastFrameTick = 0;
        int frameCount;
        float frameRate = 0;
        // Font for drawing text.
        private Microsoft.DirectX.Direct3D.Font statsFont = null;
        // Sprite for batching text calls.
        private Sprite textSprite = null;
        private bool showHelp = true;
        // HUD Elements.
        private Rectangle reticleRectangle;
        private Rectangle livesHealthBoxRectangle;
        private Rectangle weaponSelectionRectangle;
        private Rectangle digitRectangle;
        private Rectangle weaponRectangle;
        private Vector3 reticleCenter;
        private Vector3 livesHealthBoxCenter;
        private Vector3 weaponSelectionCenter;
        private Vector3 digitCenter;
        private Vector3 weaponCenter;
        public static Vector3 reticlePosition;
        public static Vector3 livesHealthBoxPosition;
        public static Vector3 livesOnePosition;
        public static Vector3 livesTwoPosition;
        public static Vector3 healthOnePosition;
        public static Vector3 healthTwoPosition;
        public static Vector3 healthThreePosition;
        public static Vector3 weaponSelectionPosition;
        public static Vector3 weaponPosition;
        public static Vector3 weaponOnePosition;
        public static Vector3 weaponTwoPosition;
        public static Vector3 weaponThreePosition;
        public static Vector3 weaponFourPosition;
        public static Vector3 weaponFivePosition;
        public static Vector3 weaponSixPosition;
        public static Vector3 weaponSevenPosition;
        public static Vector3 weaponEightPosition;
        public static Vector3 weaponNinePosition;
        public static Vector3 weaponZeroPosition;
        private Sprite reticleSprite;
        private Sprite livesHealthBoxSprite;
        private Sprite digitSprite;
        private Sprite weaponSelectionSprite;
        private Sprite weaponSprite;
        Texture reticleTex;
        Texture hudOne, hudTwo, hudThree, hudFour, hudFive, hudSix,
                hudSeven, hudEight, hudNine, hudZero, blankDigit;
        Texture hudOne_blur, hudTwo_blur, hudThree_blur, hudFour_blur, hudFive_blur,
                hudSix_blur, hudSeven_blur, hudEight_blur, hudNine_blur, hudZero_blur;
        Texture livesHealthBox, weaponSelection;
        private bool playerDead = false;

        //Wii mote stuff
        private WiimoteCollection wMc; //collection of wiimotes, as opposed to the array method
        private Wiimote playerwm; //player's wiimote
        private Wiimote camwm; //camera wiimote detected using extensiontype method

        private float IRPosx; //x position of the IR LEDS (midpoint)
        private float IRPosy; //y position of the IR LEDS (midpoint)
        private float centerIRx; //relative center x for the midpoint
        private float centerIRy; //relative center y for the midpoint
        private float lastIRDifx; //so the movement doesn't go crazy w/ slideCamera(x,y)
        private float lastIRDify; //so the movement doesn't go crazy
        private float distFromCamera; //last known ir distance
        private float prevDistFromCamera; //prev distance

        //Level information
        // Amount camera target has moved horizontally from original target.
        private float hTotalMovement;
        // Amount camera target has moved vertically from original target.
        private float vTotalMovement;
        private ArrayList textureList = new ArrayList();
        public static ArrayList entityList = new ArrayList();
        public static ArrayList projectileList = new ArrayList();
        public ArrayList toBeRemovedList = new ArrayList();
        public ArrayList toBeRemovedEntities = new ArrayList();
        private int textureIndex;
        public static LevelLoader level;
        public static Camera camera;
        public static Entity player;
        public float movementFactor = 0.1f;
        public static int currentNumEnemies;
        private bool currentlyFighting = false;

        //Stuff I don't know what it does
        private int counter = 0;
        private int weaponSelect = 0;

        // Variables relating to the player.
        private float height;
        private int fireRate = 0;
        private ArrayList playerWeapons = new ArrayList();
        private int whichWeaponSelected = 0;

        //Pause button
        private Boolean paused = false;

        /**
         * Constructor
         */
        public Game()
        {
            // Load the configuration data.
            LoadConfigData();
            // Initialize the hardware.
            InitializeDevice();
            // Setup the window.
            SetupWindow();
            // Setup the keyboard.
            InitializeKeyboard();
            // Setup the wiimote.
            initializeWiimotes();
            // Load a level with the width, height, length of the parameters.
            level = new LevelLoader(ref device, this, ref soundDevice);
            initializeHUD();
            player = level.thePlayer;
            // Set the height of the player to a value so it can be passed.
            height = 5.5f;
            // Setup the camera.
            camera = new Camera(ref device, level, movementFactor, height);
            //give the player weapons
            Weapon gun1 = new Weapon("w_gun1.txt", ref device, ref soundDevice);
            playerWeapons.Add(gun1);
            Weapon gun2 = new Weapon("w_gun2.txt", ref device, ref soundDevice);
            playerWeapons.Add(gun2);
            Weapon gun3 = new Weapon("w_gun3.txt", ref device, ref soundDevice);
            playerWeapons.Add(gun3);
            Weapon gun4 = new Weapon("w_gun4.txt", ref device, ref soundDevice);
            playerWeapons.Add(gun4);
            Weapon gun5 = new Weapon("w_gun5.txt", ref device, ref soundDevice);
            playerWeapons.Add(gun5);
            Weapon gun6 = new Weapon("w_gun6.txt", ref device, ref soundDevice);
            playerWeapons.Add(gun6);
            Weapon gun7 = new Weapon("w_gun7.txt", ref device, ref soundDevice);
            playerWeapons.Add(gun7);

            hTotalMovement = 0;
            vTotalMovement = 0;
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
            centerIRx = 0.5f;
            centerIRy = 0.5f;

            // Add an event handler for the keys that are to be toggled.
            this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnKeyPress);
        }

        /**
         * LoadConfigData - Reads configuration information from the file 
         *                    specified in this method.
         */
        private void LoadConfigData()
        {
            try {
                TextReader tr = new StreamReader("config.dat");
                String line;
                String[] values;
                char[] sC = { '=' };
                line = tr.ReadLine();
                values = line.Split(sC);
                windowed = bool.Parse(values[1]);
                line = tr.ReadLine();
                values = line.Split(sC);
                screenResolutionWidth = int.Parse(values[1]);
                line = tr.ReadLine();
                values = line.Split(sC);
                screenResolutionHeight = int.Parse(values[1]);
            } catch(FileNotFoundException) {
                Console.WriteLine("No config file found");
            }
        }

        /**
         * initializeHUD - method in which HUD elements are initialized.
         */
        private void initializeHUD()
        {
            float edgeOfScreenBuffer = 10f;
            float healthBoxPosX;
            float healthBoxPosY;
            float weaponSelectionPosX = edgeOfScreenBuffer + 158f;
            float weaponSelectionPosY;

            // Adjust the placement of HUD elements based on if the game is windowed or not.
            if(!windowed) {
                healthBoxPosX = (screenResolutionWidth - 64f - edgeOfScreenBuffer) * 1.0f;
                healthBoxPosY = (screenResolutionHeight - 32f - edgeOfScreenBuffer) * 1.0f;
                weaponPosition = new Vector3(screenResolutionWidth * .5f, screenResolutionHeight - 128f, 100f);
            } else {
                healthBoxPosX = (screenResolutionWidth - 75f - edgeOfScreenBuffer) * 1.0f;
                healthBoxPosY = (screenResolutionHeight - 65f - edgeOfScreenBuffer) * 1.0f;
                weaponPosition = new Vector3(screenResolutionWidth * .5f, screenResolutionHeight - 167f, 100f);
            }

            weaponSelectionPosY = healthBoxPosY;
            reticleRectangle = new Rectangle(0, 0, 32, 32);
            reticleCenter = new Vector3(16f, 16f, 100f);
            reticlePosition = new Vector3(screenResolutionWidth * 0.5f, screenResolutionHeight * 0.5f, 100f);
            reticleSprite = new Sprite(device);
            weaponRectangle = new Rectangle(0, 0, 256, 256);
            weaponCenter = new Vector3(128f,128f,100f);
            weaponSprite = new Sprite(device);
            livesHealthBoxRectangle = new Rectangle(0, 0, 128, 64);
            livesHealthBoxCenter = new Vector3(64f, 32f, 100f);
            livesHealthBoxPosition = new Vector3(healthBoxPosX, healthBoxPosY, 100f);
            livesHealthBoxSprite = new Sprite(device);
            // Standard digits are in reality 16 x 23.
            digitRectangle = new Rectangle(0, 0, 32, 32);
            digitCenter = new Vector3(8f, 12f, 100f);
            livesOnePosition = new Vector3(healthBoxPosX - 50f, healthBoxPosY - 5f, 100f);
            livesTwoPosition = new Vector3(healthBoxPosX - 30f, healthBoxPosY - 5f, 100f);
            healthOnePosition = new Vector3(healthBoxPosX, healthBoxPosY - 5f, 100f);
            healthTwoPosition = new Vector3(healthBoxPosX + 20f, healthBoxPosY - 5f, 100f);
            healthThreePosition = new Vector3(healthBoxPosX + 40f, healthBoxPosY - 5f, 100f);
            digitSprite = new Sprite(device);
            weaponSelectionRectangle = new Rectangle(0, 0, 512, 64);
            // weaponSelection is actually 316 x 64.
            weaponSelectionCenter = new Vector3(158f, 32f, 100f);
            weaponSelectionPosition = new Vector3(weaponSelectionPosX, weaponSelectionPosY, 100f);
            weaponSelectionSprite = new Sprite(device);
            weaponOnePosition = new Vector3(weaponSelectionPosX - 140f, weaponSelectionPosY - 5, 100f);
            weaponTwoPosition = new Vector3(weaponSelectionPosX - 118f, weaponSelectionPosY - 5, 100f);
            weaponThreePosition = new Vector3(weaponSelectionPosX - 86f, weaponSelectionPosY - 5, 100f);
            weaponFourPosition = new Vector3(weaponSelectionPosX - 54f, weaponSelectionPosY - 5, 100f);
            weaponFivePosition = new Vector3(weaponSelectionPosX - 22f, weaponSelectionPosY - 5, 100f);
            weaponSixPosition = new Vector3(weaponSelectionPosX + 10f, weaponSelectionPosY - 5, 100f);
            weaponSevenPosition = new Vector3(weaponSelectionPosX + 42f, weaponSelectionPosY - 5, 100f);
            weaponEightPosition = new Vector3(weaponSelectionPosX + 74f, weaponSelectionPosY - 5, 100f);
            weaponNinePosition = new Vector3(weaponSelectionPosX + 106f, weaponSelectionPosY - 5, 100f);
            weaponZeroPosition = new Vector3(weaponSelectionPosX + 138f, weaponSelectionPosY - 5, 100f);
        }

        /**
         * InitializeDevice - create the interface to interact with the hardware directly
         */
        private void InitializeDevice()
        {

            PresentParameters presentParms = new PresentParameters();
            presentParms.BackBufferWidth = screenResolutionWidth;
            presentParms.BackBufferHeight = screenResolutionHeight;
            presentParms.BackBufferFormat = Format.R5G6B5;
            presentParms.Windowed = windowed;
            presentParms.SwapEffect = SwapEffect.Discard;
            presentParms.AutoDepthStencilFormat = DepthFormat.D16;
            presentParms.EnableAutoDepthStencil = true;
            device = new Microsoft.DirectX.Direct3D.Device(0, Microsoft.DirectX.Direct3D.DeviceType.Hardware,
                this, CreateFlags.HardwareVertexProcessing, presentParms);
            
            device.SamplerState[0].MinFilter = TextureFilter.Anisotropic;
            device.SamplerState[0].MagFilter = TextureFilter.Anisotropic;

            device.SamplerState[0].AddressU = TextureAddress.Mirror;
            device.SamplerState[0].AddressV = TextureAddress.Mirror;
            device.RenderState.CullMode = Cull.CounterClockwise;
            device.RenderState.FillMode = FillMode.Solid;

            device.RenderState.Lighting = false;

            // Load the texture for the reticle.
            reticleTex = TextureLoader.FromFile(device, "reticle.png");
            // Load all of the textures for the values to display health/lives/weapon number.
            hudOne = TextureLoader.FromFile(device, "HUD-1,s28.png");
            hudTwo = TextureLoader.FromFile(device, "HUD-2,s28.png");
            hudThree = TextureLoader.FromFile(device, "HUD-3,s28.png");
            hudFour = TextureLoader.FromFile(device, "HUD-4,s28.png");
            hudFive = TextureLoader.FromFile(device, "HUD-5,s28.png");
            hudSix = TextureLoader.FromFile(device, "HUD-6,s28.png");
            hudSeven = TextureLoader.FromFile(device, "HUD-7,s28.png");
            hudEight = TextureLoader.FromFile(device, "HUD-8,s28.png");
            hudNine = TextureLoader.FromFile(device, "HUD-9,s28.png");
            hudZero = TextureLoader.FromFile(device, "HUD-0,s28.png");
            blankDigit = TextureLoader.FromFile(device, "HUD-BlankDigit.png");
            // Load the HUD texture which will have the health displayed in.
            livesHealthBox = TextureLoader.FromFile(device, "HUD-HealthLivesBox.png");
            // Load the HUD texture which will display the weapons the player currently does and does not have.
            weaponSelection = TextureLoader.FromFile(device, "HUD-WeaponSelection.png");
            // Load all of the textures for the blurred out versions of numbers to be displayed when the
            //   player does not have a weapon.
            hudOne_blur = TextureLoader.FromFile(device, "HUD-1-Blur,s28.png");
            hudTwo_blur = TextureLoader.FromFile(device, "HUD-2-Blur,s28.png");
            hudThree_blur = TextureLoader.FromFile(device, "HUD-3-Blur,s28.png");
            hudFour_blur = TextureLoader.FromFile(device, "HUD-4-Blur,s28.png");
            hudFive_blur = TextureLoader.FromFile(device, "HUD-5-Blur,s28.png");
            hudSix_blur = TextureLoader.FromFile(device, "HUD-6-Blur,s28.png");
            hudSeven_blur = TextureLoader.FromFile(device, "HUD-7-Blur,s28.png");
            hudEight_blur = TextureLoader.FromFile(device, "HUD-8-Blur,s28.png");
            hudNine_blur = TextureLoader.FromFile(device, "HUD-9-Blur,s28.png");
            hudZero_blur = TextureLoader.FromFile(device, "HUD-0-Blur,s28.png");

            //SOUND DEVICE
            soundDevice = new Microsoft.DirectX.DirectSound.Device();
            soundDevice.SetCooperativeLevel(this, CooperativeLevel.Normal);
            Console.WriteLine("Sound created");
        }

        /**
         * SetupWindow - Setup the window, and try to start the Wiimote.  Catch 
         *                 an exception if the Wiimote is not there so the
         *                 application can run without it
         */
        private void SetupWindow()
        {
            this.components = new System.ComponentModel.Container();
            this.Size = new System.Drawing.Size(screenResolutionWidth, screenResolutionHeight);
        }

        /**
         * InitializeKeyboard - Initialize the keyboard.
         */
        public void InitializeKeyboard()
        {
            keyboard = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
            keyboard.SetCooperativeLevel(this, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
            keyboard.Acquire();
        }

        /**
         * RenderText - Writes helpful text to the screen for the player.
         */
        private void RenderText()
        {
            statsFont = ResourceCache.GetGlobalInstance().CreateFont(device, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default, Precision.Default, FontQuality.Default, PitchAndFamily.FamilyDoNotCare | PitchAndFamily.DefaultPitch, "Arial");
            TextHelper txtHelper = new TextHelper(statsFont, textSprite, 15);
            txtHelper.Begin();
            txtHelper.SetInsertionPoint(5, 5);
            Vector3 theCoordinates = camera.getCameraPosition();
  
            // Output statistics.
            txtHelper.SetForegroundColor(System.Drawing.Color.Yellow);
            txtHelper.DrawTextLine("--Stats--");

            // Framerate business.
            frameCount++;
            if(frameCount == 100) {
                frameRate = 100 * 1000.0f / (Environment.TickCount - lastFrameTick);
                lastFrameTick = Environment.TickCount;
                frameCount = 0;
            }
            txtHelper.DrawTextLine("Avg Framerate: " + frameRate);

            // Position.
            txtHelper.DrawTextLine("X: " + theCoordinates.X);
            txtHelper.DrawTextLine("Y: " + theCoordinates.Y);
            txtHelper.DrawTextLine("Z: " + theCoordinates.Z);

            // Wiimote business.
            txtHelper.DrawTextLine("");

            txtHelper.DrawTextLine("--Controls--");
            txtHelper.DrawTextLine("Movement: WASD");
            txtHelper.DrawTextLine("Look: Arrow keys");
            txtHelper.DrawTextLine("C: Center camera");
            txtHelper.DrawTextLine("H: Enable this help menu");
            txtHelper.DrawTextLine("ESC: Quit");
            txtHelper.DrawTextLine("");
            txtHelper.DrawTextLine("Player Health: " + player.theHealth);
            Weapon temp = (Weapon)playerWeapons[whichWeaponSelected];
            txtHelper.DrawTextLine("Current Weapon's Ammo: " + temp.ammo);
            txtHelper.DrawTextLine("");

            txtHelper.End();
        }

        /**
         * readKeyboard - NEED EXPLANATION OF METHOD
         */
        public void readKeyboard()
        {
            float vPerCall = 0;
            float hPerCall = 0;

            // The keyboard.
            KeyboardState keys = keyboard.GetCurrentKeyboardState();
            /**
             * Keyboard controls.
             */
            // Rotating camera right.
            if(keys[Key.Right]) {
                hPerCall = -.05f;
                camera.rotateCamera(hPerCall, 0);
            }
            // Rotating camera left.
            if(keys[Key.Left]) {
                hPerCall = .05f;
                camera.rotateCamera(hPerCall, 0);
            }
            // Rotating camera up.
            if(keys[Key.Up]) {
                vPerCall = .05f;
                //keep camera from going too far in the y direction
                if(camera.getVRadians() < (Math.PI / 2.1)) {
                    camera.rotateCamera(0, vPerCall);
                }
            }
            // Rotating camera down.
            if(keys[Key.Down]) {
                vPerCall = -.05f;
                //keep camera from going too far in the y direction
                //2.1 was used because 2 would still go over the 90 degree mark
                //and flip everything over
                if(camera.getVRadians() > (Math.PI / 2.1 * -1)) {
                    camera.rotateCamera(0, vPerCall);
                }
            }
            // Hitting the C-button.
            if(keys[Key.C]) {  //center view
                camera.rotateCamera(0, -vTotalMovement);
                hTotalMovement = 0;
                vTotalMovement = 0;
            }
            // Move camera forward in whatever direction it is facing
            if(keys[Key.W]) {
                camera.moveCamera(.25f);
            }
            //Move camera backward in whatever direction it is facing
            if(keys[Key.S]) {
                camera.moveCamera(-.25f);
            }
            //Slide camera left (strafe)
            if(keys[Key.A]) {
                camera.slideCamera(.25f, 0);
            }
            //Slide camera right (strafe)
            if(keys[Key.D]) {
                camera.slideCamera(-.25f, 0);
            }
            // Quit the application via the Esc key.
            
            /*if(keys[Key.Escape]) {
                this.Dispose(true);
            }*/
            
            // Show the helpful text.
            /*
            if(keys[Key.H]) {
                showHelp = !showHelp;
            }
            */
            // Float up.
            if(keys[Key.Q]) {
                camera.aboutToMove();
                camera.slideCamera(0, movementFactor);
            }
            // Float down.
            if(keys[Key.Z]) {
                camera.aboutToMove();
                camera.slideCamera(0, -movementFactor);
            }
            //Shoot default projectile something
            /*if (keys[Key.Space])
            {
                Projectile testProjectile = new Projectile(player, "PlayerProjectile.txt", device);
                projectileList.Add(testProjectile);
            }*/

            // Total movement from original camera target.
            hTotalMovement += hPerCall;
            vTotalMovement += vPerCall;
        }

        private void OnKeyPress(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            // Show the helpful text.
            if((int)(byte)e.KeyCode == (int)Keys.H){
                showHelp = !showHelp;
            }
            // Quit the application via the Esc key.
            if((int)(byte)e.KeyCode == (int)Keys.Escape){
                this.Dispose(true);
            }
            if ((int)(byte)e.KeyCode == (int)Keys.Space)
            {
                Weapon temp = (Weapon)playerWeapons[whichWeaponSelected];
                temp.fire();
            }
            if((int)(byte)e.KeyCode == (int)Keys.D1) {
                whichWeaponSelected = 0;
            }
            if((int)(byte)e.KeyCode == (int)Keys.D2) {
                whichWeaponSelected = 1;
            }
            if((int)(byte)e.KeyCode == (int)Keys.D3) {
                whichWeaponSelected = 2;
            }
            if((int)(byte)e.KeyCode == (int)Keys.D4) {
                whichWeaponSelected = 3;
            }
            if((int)(byte)e.KeyCode == (int)Keys.D5) {
                whichWeaponSelected = 4;
            }
            if((int)(byte)e.KeyCode == (int)Keys.D6) {
                whichWeaponSelected = 5;
            }
            if((int)(byte)e.KeyCode == (int)Keys.D7) {
                whichWeaponSelected = 6;
            }

            if((int)(byte)e.KeyCode == (int)Keys.I) {
                //player.allowTraversal = true;
                player.continueOn = true;
                currentlyFighting = false;
                level.currentStage++;
            }

            if((int)(byte)e.KeyCode == (int)Keys.O) {
                player.tempSemaphore = false;
            }


            if((int)(byte)e.KeyCode == (int)Keys.Pause) {
                if(paused) {
                    paused = false;
                    this.Invalidate();
                } else {
                    paused = true;
                }
                Console.WriteLine("Pause is " + paused);
            }

        }

        /**
         * readWiimotes - NEED EXPLANATION OF METHOD
         */
        private void readWiimotes()
        {
            //START CAMERA WIIMOTE CODE
            float IRDist = .50f;;
            //IR POSITION OF THE IRLEDS
            if(camwm.WiimoteState.IRState.IRSensors[0].Found && camwm.WiimoteState.IRState.IRSensors[1].Found) {
                IRPosx = camwm.WiimoteState.IRState.Midpoint.X;
                IRPosy = camwm.WiimoteState.IRState.Midpoint.Y;


                IRDist = (float) Math.Sqrt(Math.Pow((double)((camwm.WiimoteState.IRState.IRSensors[0].Position.X
                            - camwm.WiimoteState.IRState.IRSensors[1].Position.X)), 2) +
                            Math.Pow((double)((camwm.WiimoteState.IRState.IRSensors[0].Position.Y
                            - camwm.WiimoteState.IRState.IRSensors[1].Position.Y)), 2));

            }
            //move camera based on how much the sensor bar has moved
            distFromCamera = 10 / IRDist;
           // camera.moveCamera((prevDistFromCamera - distFromCamera));
            prevDistFromCamera = distFromCamera;
            //set the center of where the IR leds are to keep track of how much they have moved
            float irDifX = IRPosx - centerIRx;
            float irDifY = IRPosy - centerIRy;
            //Console.WriteLine(IRPosy);
            //add restrictions here:
            //this should allow the player to only move 30 units away from the current node
            //when he/she is stopped
            //if irposx < .3 && irposx > -.3 && irposy < .3 && irposy > -.3
            //if camera position < |nodex,nodey,nodez| +30
            int node = (int)level.thePlayer.nodePointer;
            if (node == 0)
            {
                node = level.thePlayer.thePathArray.Length / 6 - 1;
            }
            else
            {
                node = node - 1;
            }
            Console.WriteLine(node);

            float curX = level.thePlayer.thePathArray[node, 2];
            float curY = level.thePlayer.thePathArray[node, 3];
            float curZ = level.thePlayer.thePathArray[node, 4];

            if (IRPosx < .8f && IRPosy < .8f && IRPosx > .2f && IRPosy > .2f)
            {

                if ((camera.cameraPosition.X - curX) < 2 && (irDifX - lastIRDifx) < 0 ||
                    (camera.cameraPosition.Z - curZ) < 2 && (irDifX - lastIRDifx) < 0)
                {
                    camera.slideCamera(10 * (irDifX - lastIRDifx), 0);
                }
                else if ((camera.cameraPosition.X - curX) > -2 && (irDifX - lastIRDifx) > 0 ||
                    (camera.cameraPosition.Z - curZ) > -2 && (irDifX - lastIRDifx) > 0)
                {
                    camera.slideCamera(20 * (irDifX - lastIRDifx), 0);
                }


                if ((camera.cameraPosition.Y - curY) > -2 && (irDifY - lastIRDify) < 0)
                {
                    camera.slideCamera(0, 20 * (irDifY - lastIRDify));
                } 
                else if ((camera.cameraPosition.Y - curY) < 2 && (irDifY - lastIRDify) > 0)
                {
                    camera.slideCamera(0, 20 * (irDifY - lastIRDify));
                }
                //camera.slideCamera(10 * (irDifX - lastIRDifx), 10 * (irDifY - lastIRDify));
            }

            lastIRDifx = irDifX;
            lastIRDify = irDifY;
            //END CAMERA WIIMOTE CODE

            //START PLAYER WIIMOTE CODE

            if (playerwm.WiimoteState.IRState.IRSensors[0].Found && playerwm.WiimoteState.IRState.IRSensors[1].Found)
            {
                reticlePosition.X= screenResolutionWidth * (1-playerwm.WiimoteState.IRState.Midpoint.X);
                reticlePosition.Y= screenResolutionHeight * playerwm.WiimoteState.IRState.Midpoint.Y;
            }

            //END PLAYER WIIMOTE CODE


            //track how much the nunchuck has moved off center of joystick horizontally
            //the negative is added so that left and right are moved correctly
            float rHorizontal = -playerwm.WiimoteState.NunchukState.Joystick.X;
            //track how much the nunchuck has moved off center of joystick vertically
            float rVertical = playerwm.WiimoteState.NunchukState.Joystick.Y;
            //camera sensitivity
            float rotateAmount = 0.03f;
            //amount to move camera each time this method is called horizontally
            float hPerCall = 0;
            //amount to move camera each time this method is called vertically
            float vPerCall = 0;

            /*
             * Wii controls.
             */

            /* surround this in an if block that tells how much the camera has moved
             * 
             * camera.slideCamera(irDifX, irDifY);
             * 
             */
            // Rotate camera Right.
            if(rHorizontal > 0.2) {
                hPerCall = rHorizontal * rotateAmount;
                camera.rotateCamera(hPerCall, 0);
            }
            // Rotate camera Left.
            if(rHorizontal < -0.2) {
                hPerCall = rHorizontal * rotateAmount;
                camera.rotateCamera(hPerCall, 0);
            }
            // Rotate camera Up.
            if(rVertical > 0.2) {
                vPerCall = rVertical * rotateAmount;
                //keep camera from going too far in the y direction
                if(camera.getVRadians() < (Math.PI / 2.1)) {
                    camera.rotateCamera(0, vPerCall);
                }

            }
            // Rotate camera Down.
            if(rVertical < -0.2) {
                vPerCall = rVertical * rotateAmount;
                //keep camera from going too far in the y direction
                if(camera.getVRadians() > (Math.PI / 2.1 * -1)) {
                    camera.rotateCamera(0, vPerCall);
                }
            }
            // Hitting the Z-button.
            if(playerwm.WiimoteState.NunchukState.Z) {
                camera.moveCamera(.1f);
            }
            // Hitting the C-button.
            if(playerwm.WiimoteState.NunchukState.C) {  //center view
                camera.rotateCamera(-hTotalMovement, -vTotalMovement);
                hTotalMovement = 0;
                vTotalMovement = 0;
                //resets the center point of the sensorbar
                centerIRx = IRPosx;
                centerIRy = IRPosy;
            }
            //wiimote dpad is forward,left,right,back
            // Move camera forward in whatever direction it is facing
            if(playerwm.WiimoteState.ButtonState.Up) {
                camera.moveCamera(.1f);
            }
            //Move camera backward in whatever direction it is facing
            if(playerwm.WiimoteState.ButtonState.Down) {
                camera.moveCamera(-.1f);
            }
            //Slide camera left (strafe)
            if(playerwm.WiimoteState.ButtonState.Left) {
                camera.slideCamera(.1f, 0);
            }
            //Slide camera right (strafe)
            if(playerwm.WiimoteState.ButtonState.Right) {
                camera.slideCamera(-.1f, 0);
            }
            //if b is pressed, fire projectile
            if(playerwm.WiimoteState.ButtonState.B) {
                if (fireRate == 0){
                    Weapon temp = (Weapon)playerWeapons[whichWeaponSelected];
                    temp.fire();
                    playerwm.SetRumble(true);
                }
                fireRate++;
                fireRate %= 20;
            }
            if (!playerwm.WiimoteState.ButtonState.B){
                fireRate = 0;
                playerwm.SetRumble(false);
            }

            //FIRE
            if (playerwm.WiimoteState.ButtonState.Plus)
            {
                if (weaponSelect == 0)
                {
                    Weapon temp = (Weapon)playerWeapons[whichWeaponSelected];
                    if (whichWeaponSelected > 5)
                    {
                        whichWeaponSelected = 0;
                    }
                    else
                    {
                        whichWeaponSelected++;
                    }
                }
                weaponSelect++;
                weaponSelect %= 300;
            }
            if (!playerwm.WiimoteState.ButtonState.Plus)
            {
                weaponSelect = 0;
            }





            hTotalMovement += hPerCall;
            vTotalMovement += vPerCall;
            //END
        }

        /**
         * initializeWiimotes - This method initializes finds and initializes 
         *   all of the wiimotes so that each wiimote has an assigned purpose.
         *   This code only allows for 2 wiimotes to be connected at a time,
         *   and also one has to have a nunchuck attached, otherwise the 
         *   program will crash with a null pointer.
         */
        private void initializeWiimotes()
        {
            IRPosy = new float();
            IRPosx = new float();
            centerIRx = new float();
            centerIRy = new float();

            wMc = new WiimoteCollection();
            try {
                wMc.FindAllWiimotes();
            } catch(WiimoteNotFoundException ex) {
                Console.WriteLine(ex.Message + "\nWiimote not found error");
            } catch(WiimoteException ex) {
                Console.WriteLine(ex.Message + "\nWiimote error");
            } catch(Exception ex) {
                Console.WriteLine(ex.Message + "\nUnknown error");
            }

            foreach(Wiimote wiimote in wMc) {
                wiimote.Connect();
                if(wiimote.WiimoteState.ExtensionType.Equals(ExtensionType.Nunchuk)) {
                    playerwm = wiimote;
                    playerwm.SetLEDs(15);
                    wiimote.SetReportType(InputReport.IRExtensionAccel, true);
                } else {
                    camwm = wiimote;
                    camwm.SetLEDs(1);
                    wiimote.SetReportType(InputReport.Buttons, true);

                    //sets the default value of the center of the camera or where the person is standing
                    if(camwm.WiimoteState.IRState.IRSensors[0].Found && camwm.WiimoteState.IRState.IRSensors[1].Found) {
                        centerIRx = camwm.WiimoteState.IRState.Midpoint.X;
                        centerIRy = camwm.WiimoteState.IRState.Midpoint.Y;
                    } else {
                        centerIRx = 0;
                        centerIRx = 0;
                    }
                }

            }
        }

        /**
         * ReadInput - Read the input, either from the keyboard or the wiimote.
         */
        private void ReadInput()
        {
            //readWiimotes();
            readKeyboard();
            camera.changeCamera();
            player.centerCoords = camera.getCameraPosition();
        }

        /**
         * OnPaint - Does all the painting on the application.  As soon as it
         *             executes, it calls itself and runs again.
         * @param e - NEED EXPLANATION OF PARAMETER.
         */
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkSlateBlue, 1.0f, 0);
            device.BeginScene();
            /*if(level.wallList.Count > 0) 
            {
                device.VertexFormat = CustomVertex.PositionColored.Format;
                device.DrawUserPrimitives(PrimitiveType.TriangleList, level.wallList.Count / 3, level.verticesArray);
            }*/
            //draw textured walls
            if(level.wallListTextured.Count > 0) 
            {
                device.VertexFormat = CustomVertex.PositionNormalTextured.Format;
                textureIndex = 0;
                foreach(ArrayList t in level.wallListTextured) 
                {
                    CustomVertex.PositionNormalTextured[] z = (CustomVertex.PositionNormalTextured[])t.ToArray(typeof(CustomVertex.PositionNormalTextured));
                    device.SetTexture(0, (Texture)level.textures[textureIndex]);
                    textureIndex++;
                    device.DrawUserPrimitives(PrimitiveType.TriangleList, 2, z);
                }
            }

            /*if (level.wallListTextured.Count > 0)
            {
                device.VertexFormat = CustomVertex.PositionNormalTextured.Format;
                device.SetStreamSource(0, level.vb, 0);
                device.SetTexture(0, (Texture)level.textures[0]);
                //for (int i = 0; i < textIndex; i++)
                //{
                    device.DrawUserPrimitives(PrimitiveType.TriangleList, level.verticesTextured.Length / 3, level.verticesTextured);
                //}
            }*/

            /*
            // If the player has eliminated all of the enemies, then they can pass to the next level.
            if(currentNumEnemies == 0 && currentlyFighting) {
                Console.WriteLine("Inside: currentNumEnemies == 0 && currentlyFighting");
                player.allowTraversal = true;
                currentlyFighting = false;
                level.currentStage++;
                player.alreadyAccessed[(int)player.nodePointer] = false;
            }
            */

            // If the player has gone around the path completely (or just started), set
            //   the 'currentStage' appropriately.
            if(player.setCurrentStageToZero) {
                level.currentStage = 0;
                player.setCurrentStageToZero = false;
            }

            // If the player has advanced to a new stage, add the appropriate enemies.
            if(!player.continueOn && player.spawnEnemies && 
               player.alreadyAccessed[(int)player.nodePointer]) {
                advanceToNextStage();
                player.spawnEnemies = false;
            }

            // If the player has defeated the enemies in the current stage, continue along path.
            if(currentlyFighting && currentNumEnemies == 0) {
                player.continueOn = true;
                currentlyFighting = false;
                level.currentStage++;
                
                if (wMc.Count > 0)
                {
                    camwm.SetReportType(InputReport.Buttons, true);
                }

                camera.cameraPosition.X = player.centerCoords.X = player.thePathArray[(int)player.nodePointer, 2];
                camera.cameraPosition.Y = player.centerCoords.Y = player.thePathArray[(int)player.nodePointer, 3];
                camera.cameraPosition.Z = player.centerCoords.Z = player.thePathArray[(int)player.nodePointer, 4];

            }

            if (entityList.Count > 0) {
                device.VertexFormat = CustomVertex.PositionNormalTextured.Format;
                device.RenderState.AlphaBlendEnable = true;
                device.RenderState.AlphaFunction = Compare.Greater;
                device.RenderState.AlphaTestEnable = true;
                device.RenderState.DestinationBlend = Blend.InvSourceAlpha;
                device.RenderState.SourceBlend = Blend.SourceAlpha;
                device.RenderState.DiffuseMaterialSource = ColorSource.Material;

                //Color blending ops
                device.TextureState[0].ColorOperation = TextureOperation.Modulate;
                device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
                device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;

                //set the first alpha stage to texture alpha
                device.TextureState[0].AlphaOperation = TextureOperation.SelectArg1;
                device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;
                foreach (Entity t in entityList)
                {
                    float xDiff = player.centerCoords.X - t.centerCoords.X;
                    float zDiff = player.centerCoords.Z - t.centerCoords.Z;
                    t.theAngle = (float)Math.Atan2((double)zDiff, (double)xDiff) + (float)Math.PI / 2;
                    device.SetTexture(0, t.texture);
                    device.DrawUserPrimitives(PrimitiveType.TriangleList, 2, t.spriteArray);
                }

                foreach (Projectile p in projectileList)
                {
                    float xDiff = player.centerCoords.X - p.centerCoords.X;
                    float zDiff = player.centerCoords.Z - p.centerCoords.Z;
                    p.theAngle = (float)Math.Atan2((double)zDiff, (double)xDiff) + (float)Math.PI / 2;
                    device.SetTexture(0, p.texture);
                    device.DrawUserPrimitives(PrimitiveType.TriangleList, 2, p.spriteArray);
                }
            }
            //Draw the weapon on the HUD
            Weapon temp = (Weapon)playerWeapons[whichWeaponSelected];
            weaponSprite.Begin(SpriteFlags.AlphaBlend);
            weaponSprite.Draw(temp.weaponTexture, weaponRectangle, weaponCenter, weaponPosition, Color.White.ToArgb());
            weaponSprite.End();
            // Draw the reticle on the HUD.
            reticleSprite.Begin(SpriteFlags.AlphaBlend);
            reticleSprite.Draw(reticleTex, reticleRectangle, reticleCenter, reticlePosition, Color.White.ToArgb());
            reticleSprite.End();
            // Draw the healthBox on the HUD.
            livesHealthBoxSprite.Begin(SpriteFlags.AlphaBlend);
            livesHealthBoxSprite.Draw(livesHealthBox, livesHealthBoxRectangle, livesHealthBoxCenter, livesHealthBoxPosition, Color.White.ToArgb());
            livesHealthBoxSprite.End();
            // Draw the player's lives in the healthBox.
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(hudZero, digitRectangle, digitCenter, livesOnePosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(hudZero, digitRectangle, digitCenter, livesTwoPosition, Color.White.ToArgb());
            digitSprite.End();
            // Draw the players health in the healthBox.
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getHealthDigit(1), digitRectangle, digitCenter, healthOnePosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getHealthDigit(2), digitRectangle, digitCenter, healthTwoPosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getHealthDigit(3), digitRectangle, digitCenter, healthThreePosition, Color.White.ToArgb());
            digitSprite.End();
            // Draw the weaponSelection box on the HUD.
            weaponSelectionSprite.Begin(SpriteFlags.AlphaBlend);
            weaponSelectionSprite.Draw(weaponSelection, weaponSelectionRectangle, weaponSelectionCenter, weaponSelectionPosition, Color.White.ToArgb());
            weaponSelectionSprite.End();
            // Render the weapon numbers as clear or blurred based on whether the player has them or not.
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(1), digitRectangle, digitCenter, weaponOnePosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(2), digitRectangle, digitCenter, weaponTwoPosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(3), digitRectangle, digitCenter, weaponThreePosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(4), digitRectangle, digitCenter, weaponFourPosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(5), digitRectangle, digitCenter, weaponFivePosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(6), digitRectangle, digitCenter, weaponSixPosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(7), digitRectangle, digitCenter, weaponSevenPosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(8), digitRectangle, digitCenter, weaponEightPosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(9), digitRectangle, digitCenter, weaponNinePosition, Color.White.ToArgb());
            digitSprite.End();
            digitSprite.Begin(SpriteFlags.AlphaBlend);
            digitSprite.Draw(getWeaponStatus(10), digitRectangle, digitCenter, weaponZeroPosition, Color.White.ToArgb());
            digitSprite.End();

            // Render the on-screen help text.
            if(showHelp) {
                RenderText();
            }

            LOLZ();

            device.EndScene();
            device.Present();
        }

        /**
         * getHealthDigit - a method which returns a texture to represent the digit specified of the user's health.
         * @param theDigit - the value.  If health was 100, and you wanted the first digit you would pass "1".
         * @return toReturn - a texture representing the value of the player's health.
         */
        private Texture getHealthDigit(int theDigit)
        {
            string digitString = player.theHealth.ToString();
            int theDigitAdjusted;
            Texture toReturn = blankDigit;

            // If the player's health is 0, the player is dead.
            if(digitString == "0") {
                playerDead = true;
            }
            // If the player's health is double digits and 'theDigit' is asking for
            //   the hundreds place value, return an instance of 'blankDigit'.
            if(theDigit == 1 && digitString.Length == 2) {
                return toReturn;
            }
            // Adjust the requested value because it will be used to access an
            //   array and you do not want to go out of the bounds of it.
            if(digitString.Length == 2) {
                theDigitAdjusted = theDigit - 1;
            } else {
                theDigitAdjusted = theDigit;
            }
            // If the player is dead, return an instance of 'hudZero' otherwise
            //   figure out the correct the texture to send.
            if(playerDead) {
                toReturn = hudZero;
            } else if((digitString.Length == 1 && theDigit == 1) || digitString.Length == 2 || digitString.Length == 3) {
                if(digitString.Substring(theDigitAdjusted - 1, 1) == "1") {
                    toReturn = hudOne;
                } else if(digitString.Substring(theDigitAdjusted - 1, 1) == "2") {
                    toReturn = hudTwo;
                } else if(digitString.Substring(theDigitAdjusted - 1, 1) == "3") {
                    toReturn = hudThree;
                } else if(digitString.Substring(theDigitAdjusted - 1, 1) == "4") {
                    toReturn = hudFour;
                } else if(digitString.Substring(theDigitAdjusted - 1, 1) == "5") {
                    toReturn = hudFive;
                } else if(digitString.Substring(theDigitAdjusted - 1, 1) == "6") {
                    toReturn = hudSix;
                } else if(digitString.Substring(theDigitAdjusted - 1, 1) == "7") {
                    toReturn = hudSeven;
                } else if(digitString.Substring(theDigitAdjusted - 1, 1) == "8") {
                    toReturn = hudEight;
                } else if(digitString.Substring(theDigitAdjusted - 1, 1) == "9") {
                    toReturn = hudNine;
                } else if(digitString.Substring(theDigitAdjusted - 1, 1) == "0") {
                    toReturn = hudZero;
                }
            }
            return toReturn;
        }

        /**
         * getWeaponStatus - returns a texture representation of the players weapon.  If they have it the texture
         *   will be a clear number representing the weapon number.  If they do not have it the texture will be
         *   a blurred version of the weapon number.
         * @param weaponNumber - the weapon number in the playerWeapons ArrayList.
         * @return toReturn - the texture representation.
         */
        private Texture getWeaponStatus(int weaponNumber)
        {
            Texture toReturn = blankDigit;
            int numWeapons = playerWeapons.Count;

            // If the parameter passed is the value of a weapon the player
            //   does not have, return a blurred version of the number;
            //   otherwise return the appropriate texture representation.
            if(weaponNumber > numWeapons) {
                if(weaponNumber == 1) {
                    toReturn = hudOne_blur;
                } else if(weaponNumber == 2) {
                    toReturn = hudTwo_blur;
                } else if(weaponNumber == 3) {
                    toReturn = hudThree_blur;
                } else if(weaponNumber == 4) {
                    toReturn = hudFour_blur;
                } else if(weaponNumber == 5) {
                    toReturn = hudFive_blur;
                } else if(weaponNumber == 6) {
                    toReturn = hudSix_blur;
                } else if(weaponNumber == 7) {
                    toReturn = hudSeven_blur;
                } else if(weaponNumber == 8) {
                    toReturn = hudEight_blur;
                } else if(weaponNumber == 9) {
                    toReturn = hudNine_blur;
                } else if(weaponNumber == 10) {
                    toReturn = hudZero_blur;
                }
            } else {
                if(weaponNumber == 1) {
                    toReturn = hudOne;
                } else if(weaponNumber == 2) {
                    toReturn = hudTwo;
                } else if(weaponNumber == 3) {
                    toReturn = hudThree;
                } else if(weaponNumber == 4) {
                    toReturn = hudFour;
                } else if(weaponNumber == 5) {
                    toReturn = hudFive;
                } else if(weaponNumber == 6) {
                    toReturn = hudSix;
                } else if(weaponNumber == 7) {
                    toReturn = hudSeven;
                } else if(weaponNumber == 8) {
                    toReturn = hudEight;
                } else if(weaponNumber == 9) {
                    toReturn = hudNine;
                } else if(weaponNumber == 10) {
                    toReturn = hudZero;
                }
            }

            return toReturn;
        }

        /**
         * Dispose - Close the application.
         * @param disposing - NEED EXPLANATION OF PARAMETER.
         */
        protected override void Dispose(bool disposing)
        {
            if(disposing) {
                if(components != null) {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        /**
         * Game Loop method
         */ 
        public void LOLZ()
        {
            if(!paused)
                this.Invalidate();
            if (counter == 0)
            {
                foreach (Entity t in entityList)
                {
                    t.move();
                    if (t.removeMe)
                    {
                        toBeRemovedEntities.Add(t);
                    }
                }
                foreach (Projectile p in projectileList)
                {
                    p.move();
                    p.theAngle += .5f;
                    if(p.removeMe) 
                    {
                        toBeRemovedList.Add(p);
                    }
                }
                foreach(Projectile p in toBeRemovedList) 
                {
                    projectileList.Remove(p);
                }
                foreach (Entity t in toBeRemovedEntities)
                {
                    entityList.Remove(t);
                }
                toBeRemovedList.Clear();
                toBeRemovedEntities.Clear();
            }
            counter = (counter + 1) % 4;
            ReadInput();
        }

        /**
         * advanceToNextStage - method called by the player entity when they
         *   reach a point in their path and need to advance to the next
         *   stage.
         */
        public void advanceToNextStage()
        {
            currentNumEnemies = level.levelStages[level.currentStage].Length;
            for(int i = 0; i < currentNumEnemies; i++) 
            {
                Entity tempAccess = level.levelStages[level.currentStage][i];
                Entity temp = new Entity(tempAccess.thePathArray, tempAccess.theName, ref tempAccess.device, tempAccess.theAngle, ref tempAccess.soundDevice);
                entityList.Add(temp);
            }
            Console.WriteLine("Stage: " + level.currentStage + ", Enemies: " + currentNumEnemies);
            currentlyFighting = true;
            if (wMc.Count > 0)
            {
                camwm.SetReportType(InputReport.IRAccel, true);
            }
        }

        /**
         * Main - Main method of the Test3D class.
         * @param args - Parameters, if necessary.
         */
        static void Main(String[] args)
        {
            using(Game window = new Game()) {
                Application.Run(window);
            }
        }
    }
}
